home *** CD-ROM | disk | FTP | other *** search
- ------------------------------------------------------------------------------
- -- --
- -- GNAT RUNTIME COMPONENTS --
- -- --
- -- A D A . S E Q U E N T I A L _ I O --
- -- --
- -- B o d y --
- -- --
- -- $Revision: 1.4 $ --
- -- --
- -- Copyright (c) 1992,1993,1994 NYU, All Rights Reserved --
- -- --
- -- The GNAT library is free software; you can redistribute it and/or modify --
- -- it under terms of the GNU Library General Public License as published by --
- -- the Free Software Foundation; either version 2, or (at your option) any --
- -- later version. The GNAT library is distributed in the hope that it will --
- -- be useful, but WITHOUT ANY WARRANTY; without even the implied warranty --
- -- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU --
- -- Library General Public License for more details. You should have --
- -- received a copy of the GNU Library General Public License along with --
- -- the GNAT library; see the file COPYING.LIB. If not, write to the Free --
- -- Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. --
- -- --
- ------------------------------------------------------------------------------
-
- with Ada.Storage_IO;
- with Interfaces.C; use Interfaces.C;
- with Interfaces.C.Strings; use Interfaces.C.Strings;
- with System.File_Aux; use System.File_Aux;
-
- package body Ada.Sequential_IO is
-
- package Stor_IO is new Ada.Storage_IO (Element_Type => Element_Type);
-
- type Pstring is access String;
-
- type File_Control_Block is record
- Name : chars_ptr := Null_Ptr;
- Mode : File_Mode;
- Form : Pstring;
- Descriptor : C_File_Ptr;
- Byte_Size : C_Long_Int;
- Byte_Index : C_Long_Int;
- end record;
-
- type Open_Type is (Create, Open);
-
- type C_Mode_Type is array (Open_Type, File_Mode) of chars_ptr;
-
- C_Mode : C_Mode_Type := (others => (others => Null_Ptr));
-
- Buffer : Stor_IO.Buffer_Type;
-
- -----------------------
- -- Local Subprograms --
- -----------------------
-
- procedure Confirm_File_Is_Open (File : in File_Type);
- pragma Inline (Confirm_File_Is_Open);
- -- Checks to make sure the given file is open.
- -- If not, it raises Status_Error.
-
- procedure Confirm_File_Is_Closed (File : in File_Type);
- pragma Inline (Confirm_File_Is_Closed);
- -- Checks to make sure the given file is closed.
- -- If not, it raises Status_Error.
-
- function Current_Size_Of (File : in File_Type) return C_Long_Int;
- -- Returns the current size in bytes of the external file that is
- -- associated with the given file. The given file must be open.
-
- function New_Temp_File_Name return chars_ptr;
- -- Returns a name that is a valid file name and that is not the same as
- -- the name of an existing external file.
-
- function File_Exists (Name : in String) return Boolean;
- -- Returns True if an external file of the given name exists.
- -- Otherwise, it returns False.
-
- -----------
- -- Close --
- -----------
-
- procedure Close (File : in out File_Type) is
- begin
- Confirm_File_Is_Open (File);
-
- if C_Fclose (File.Descriptor) /= 0 then
- raise Device_Error;
- end if;
-
- File := null;
- end Close;
-
- --------------------------
- -- Confirm_File_Is_Open --
- --------------------------
-
- procedure Confirm_File_Is_Open (File : in File_Type) is
- begin
- if not Is_Open (File) then
- raise Status_Error;
- end if;
- end Confirm_File_Is_Open;
-
- ----------------------------
- -- Confirm_File_Is_Closed --
- ----------------------------
-
- procedure Confirm_File_Is_Closed (File : in File_Type) is
- begin
- if Is_Open (File) then
- raise Status_Error;
- end if;
- end Confirm_File_Is_Closed;
-
- ------------
- -- Create --
- ------------
-
- procedure Create
- (File : in out File_Type;
- Mode : in File_Mode := Out_File;
- Name : in String := "";
- Form : in String := "")
- is
- begin
- Confirm_File_Is_Closed (File);
- File := new File_Control_Block;
-
- -- A null string for Name specifies creation of a temporary file.
-
- if Name'Length = 0 then
- File.Name := New_Temp_File_Name;
- else
- File.Name := New_String (Name);
- end if;
-
- File.Descriptor := C_Fopen (Filename => File.Name,
- Mode => C_Mode (Create, Mode));
-
- -- If the C fopen call fails, it returns a null pointer.
-
- if C_Void_Ptr (File.Descriptor) = C_Null then
- raise Name_Error;
- end if;
-
- File.Mode := Mode;
- File.Form := new String'(Form);
-
- -- The size of the external file is required in order to avoid
- -- lookahead. In C, the end-of-file indicator is not considered to
- -- be true until after an attempt is made to read past the end of the
- -- external file. In Ada, the End_Of_File function returns True if no
- -- more elements can be read (i.e. when reading elements, End_Of_File
- -- becomes True before a failed read caused by end-of-file). In
- -- Sequential_IO, it is sufficient to determine the size of the
- -- external file once at the time of the opening of the file. The
- -- End_Of_File function only operates on a file of mode In_File, and
- -- such a file will not change in size.
-
- File.Byte_Size := Current_Size_Of (File);
- File.Byte_Index := 0;
- end Create;
-
- ---------------------
- -- Current_Size_Of --
- ---------------------
-
- function Current_Size_Of (File : in File_Type) return C_Long_Int is
- Current_Byte_Index : C_Long_Int;
- Current_Byte_Size : C_Long_Int;
-
- begin
- Current_Byte_Index := C_Ftell (File.Descriptor);
-
- if C_Fseek (Stream => File.Descriptor,
- Offset => 0,
- Whence => C_Seek_End) /= 0 then
- raise Device_Error;
- end if;
-
- Current_Byte_Size := C_Ftell (File.Descriptor);
-
- if C_Fseek (Stream => File.Descriptor,
- Offset => Current_Byte_Index,
- Whence => C_Seek_Set) /= 0 then
- raise Device_Error;
- end if;
-
- return Current_Byte_Size;
- end Current_Size_Of;
-
- ------------
- -- Delete --
- ------------
-
- procedure Delete (File : in out File_Type) is
- File_Name_To_Delete : chars_ptr;
-
- begin
- Confirm_File_Is_Open (File);
-
- -- The file should be closed before calling the C remove function.
- -- If the file is open, the behavior of the remove function is
- -- implementation-defined. Closing the file, however, means we
- -- lose the info in the file control block, so we have to save the
- -- file name temporarily in order to have it for use with the remove
- -- function.
-
- File_Name_To_Delete := File.Name;
- Close (File);
-
- if C_Remove (File_Name_To_Delete) /= 0 then
- raise Use_Error;
- end if;
- end Delete;
-
- -----------------
- -- End_Of_File --
- -----------------
-
- function End_Of_File (File : in File_Type) return Boolean is
- begin
- Confirm_File_Is_Open (File);
-
- if File.Mode /= In_File then
- raise Mode_Error;
- end if;
-
- return File.Byte_Index >= File.Byte_Size;
- end End_Of_File;
-
- -----------------
- -- File_Exists --
- -----------------
-
- function File_Exists (Name : in String) return Boolean is
- File_Descriptor : C_File_Ptr;
- C_Name : chars_ptr;
-
- begin
- C_Name := New_String (Name);
- File_Descriptor := C_Fopen (Filename => C_Name,
- Mode => C_Mode (Open, In_File));
-
- if C_Void_Ptr (File_Descriptor) = C_Null then
- return False;
- end if;
-
- if C_Fclose (File_Descriptor) /= 0 then
- raise Device_Error;
- end if;
-
- return True;
- end File_Exists;
-
- ----------
- -- Form --
- ----------
-
- function Form (File : in File_Type) return String is
- begin
- Confirm_File_Is_Open (File);
- return File.Form.all;
- end Form;
-
- -------------
- -- Is_Open --
- -------------
-
- function Is_Open (File : in File_Type) return Boolean is
- begin
- return File /= null;
- end Is_Open;
-
- ----------
- -- Mode --
- ----------
-
- function Mode (File : in File_Type) return File_Mode is
- begin
- Confirm_File_Is_Open (File);
- return File.Mode;
- end Mode;
-
- ----------
- -- Name --
- ----------
-
- function Name (File : in File_Type) return String is
- begin
- Confirm_File_Is_Open (File);
- return Value (File.Name);
- end Name;
-
- ------------------------
- -- New_Temp_File_Name --
- ------------------------
-
- function New_Temp_File_Name return chars_ptr is
- Temp_File_Name : String := "ADATMPXX";
- C_Temp_File_Name : chars_ptr;
-
- begin
- C_Temp_File_Name := New_String (Temp_File_Name);
- C_Temp_File_Name := C_Mktemp (C_Temp_File_Name);
- return C_Temp_File_Name;
- end New_Temp_File_Name;
-
- ----------
- -- Open --
- ----------
-
- procedure Open
- (File : in out File_Type;
- Mode : in File_Mode;
- Name : in String;
- Form : in String := "")
- is
- begin
- Confirm_File_Is_Closed (File);
-
- -- The language standard specifies that Name_Error must be raised if
- -- no external file with the given name exists. This should occur
- -- regardless of the given mode. The mode argument to the C fopen
- -- function does not have sufficient flexibility to handle this
- -- behavior with one call to fopen. In particular, opening a file with
- -- mode Out_File should fail if the external file does not exist, but
- -- should open and truncate the external file if it exists. The C
- -- fopen funcation has no direct equivalent of this, as an fopen with
- -- write mode succeeds whether the file exists or not. In order to
- -- get the desired behavior in Ada, we need to do a separate check for
- -- file existence prior to the C fopen call to open the file.
-
- if not File_Exists (Name) then
- raise Name_Error;
- end if;
-
- File := new File_Control_Block;
-
- File.Name := New_String (Name);
- File.Descriptor := C_Fopen (Filename => File.Name,
- Mode => C_Mode (Open, Mode));
-
- -- If the C fopen call fails, it returns a null pointer.
-
- if C_Void_Ptr (File.Descriptor) = C_Null then
- raise Name_Error;
- end if;
-
- File.Mode := Mode;
- File.Form := new String'(Form);
-
- -- The size of the external file is required in order to avoid
- -- lookahead. In C, the end-of-file indicator is not considered to
- -- be true until after an attempt is made to read past the end of the
- -- external file. In Ada, the End_Of_File function returns True if no
- -- more elements can be read (i.e. when reading elements, End_Of_File
- -- becomes True before a failed read caused by end-of-file). In
- -- Sequential_IO, it is sufficient to determine the size of the
- -- external file once at the time of the opening of the file. The
- -- End_Of_File function only operates on a file of mode In_File, and
- -- such a file will not change in size.
-
- File.Byte_Size := Current_Size_Of (File);
- File.Byte_Index := 0;
- end Open;
-
- ----------
- -- Read --
- ----------
-
- procedure Read (File : in File_Type; Item : out Element_Type) is
- begin
- Confirm_File_Is_Open (File);
-
- if File.Mode /= In_File then
- raise Mode_Error;
- end if;
-
- if End_Of_File (File) then
- raise End_Error;
- end if;
-
- -- The C fread function returns the number of elements successfully
- -- read. Since we only read one element at a time and we have already
- -- checked for end of file, if the number of elements successfully read
- -- does not equal the number of elements requested, it is considered to
- -- be a Device_Error.
-
- if C_Fread (Ptr => C_Void_Ptr (Buffer'Address),
- Size => C_Size_T (Buffer'Length),
- Nmemb => 1,
- Stream => File.Descriptor) /= 1
- then
- raise Device_Error;
- end if;
-
- -- Advance the byte index so we can check for end of file.
-
- File.Byte_Index := File.Byte_Index + Buffer'Length;
-
- Stor_IO.Read (Buffer, Item);
- end Read;
-
- -----------
- -- Reset --
- -----------
-
- procedure Reset (File : in out File_Type; Mode : in File_Mode) is
- Old_File : File_Type := File;
-
- begin
- Confirm_File_Is_Open (File);
- Close (File);
- Open (File, Mode, Value (Old_File.Name), Old_File.Form.all);
- end Reset;
-
- procedure Reset (File : in out File_Type) is
- begin
- Confirm_File_Is_Open (File);
- Reset (File, File.Mode);
- end Reset;
-
- -----------
- -- Write --
- -----------
-
- procedure Write (File : in File_Type; Item : in Element_Type) is
- begin
- Confirm_File_Is_Open (File);
-
- if File.Mode = In_File then
- raise Mode_Error;
- end if;
-
- Stor_IO.Write (Buffer, Item);
-
- -- The C fwrite function returns the number of elements successfully
- -- written, which will less than the number of elements requested only
- -- if a write error is encountered. Such a situation is considered to
- -- be a Device_Error.
-
- if C_Fwrite (Ptr => C_Void_Ptr (Buffer'Address),
- Size => C_Size_T (Buffer'Length),
- Nmemb => 1,
- Stream => File.Descriptor) /= 1
- then
- raise Device_Error;
- end if;
- end Write;
-
- begin
- -------------------------
- -- Package Elaboration --
- -----------------
- -- The following possible modes for the C fopen function are given here
- -- for reference:
- --
- -- r open text file for reading
- -- w truncate to zero length or create text file for writing
- -- a append; open or create text file for writing at end-of-file
- -- rb open binary file for reading
- -- wb truncate to zero length or create binary file for writing
- -- ab append; open or create binary file for writing at end-of-file
- -- r+ open text file for update (reading and writing)
- -- w+ truncate to zero length or create text file for update
- -- a+ append; open or create text file for update, writing at end-of-file
- -- rb+ open binary file for update (reading and writing)
- -- wb+ truncate to zero length or create binary file for update
- -- ab+ append; open or create binary file for update, writing at
- -- end-of-file
- --
- -- Notes:
- --
- -- (1) Opening a file with read mode fails if the file does not exist or
- -- cannot be read.
- --
- -- (2) Opening a file with append mode causes all subsequent writes to the
- -- file to be forced to the then current end-of-file, regardless of
- -- intervening calls to the fseek function.
- --
- -- (3) When a file is opened with update mode, both input and output may be
- -- performed on the associated stream. However, output may not be directly
- -- followed by input without an intervening call to the fflush function or
- -- to a file positioning function (fseek, fsetpos, or rewind), and input
- -- may not be directly followed by output without an intervening call to a
- -- file positioning function, unless the input operation encounters
- -- end-of-file.
-
- C_Mode (Create, In_File) := New_String ("wb");
- C_Mode (Create, Out_File) := New_String ("wb");
- C_Mode (Create, Append_File) := New_String ("wb");
-
- C_Mode (Open, In_File) := New_String ("rb");
- C_Mode (Open, Out_File) := New_String ("wb");
- C_Mode (Open, Append_File) := New_String ("ab");
- end Ada.Sequential_IO;
-